/**
 * @file   AbstractSimpleNode.cpp
 * @author Djuro Drljaca (djurodrljaca@gmail.com)
 * @date   2014-04-30
 * @brief  Brief description of file.
 *
 * Copyright 2014  Djuro Drljaca (djurodrljaca@gmail.com)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <DON/Core/Node/AbstractSimpleNode.h>
#include <DON/Core/Packet/GenericPacket.h>
#include <DON/Core/Packet/RegistrationRequestPacket.h>
#include <DON/Core/Packet/RegistrationResponsePacket.h>
#include <DON/Core/Packet/GetPropertyValueRequestPacket.h>
#include <DON/Core/Packet/GetPropertyValueResponsePacket.h>
#include <QtCore/QList>
#include <QtCore/QString>

using namespace DON::Core::Node;
using namespace DON::Core::DataType;
using namespace DON::Core::Packet;

AbstractSimpleNode::AbstractSimpleNode()
    : AbstractNode()
{
}

AbstractSimpleNode::~AbstractSimpleNode()
{
}

bool AbstractSimpleNode::isValid() const
{
    return AbstractNode::isValid();
}

int AbstractSimpleNode::getPropertyCount() const
{
    return 0;
}

DataType AbstractSimpleNode::getPropertyDataType(const quint16, bool *ok) const
{
    if (ok != NULL)
    {
        *ok = false;
    }

    return DataType_Invalid;
}

AccessModifier AbstractSimpleNode::getPropertyAccessModifier(const quint16, bool *ok) const
{
    if (ok != NULL)
    {
        *ok = false;
    }

    return AccessModifier_Invalid;
}

QString AbstractSimpleNode::getPropertyName(const quint16, bool *ok) const
{
    if (ok != NULL)
    {
        *ok = false;
    }

    return QString();
}

const AbstractDataType * AbstractSimpleNode::getPropertyValue(const quint16, bool *ok) const
{
    if (ok != NULL)
    {
        *ok = false;
    }

    return NULL;
}

bool AbstractSimpleNode::setPropertyValue(const quint16, const DataType::AbstractDataType &)
{
    return false;
}

void AbstractSimpleNode::handleReceivedPacket(const GenericPacket &receivedPacket)
{
    if (receivedPacket.isValid())
    {
        switch (receivedPacket.getPacketType())
        {
            case PacketType_RegistrationRequest:
            {
                RegistrationRequestPacket packet =
                        RegistrationRequestPacket::fromGenericPacket(receivedPacket);

                if (packet.isValid())
                {
                    handleReceivedRegistrationRequestPacket(packet);
                }
                break;
            }

            case PacketType_RegistrationResponse:
            {
                RegistrationResponsePacket packet =
                        RegistrationResponsePacket::fromGenericPacket(receivedPacket);

                if (packet.isValid())
                {
                    handleReceivedRegistrationResponsePacket(packet);
                }
                break;
            }

            case PacketType_GetPropertyValueRequest:
            {
                GetPropertyValueRequestPacket packet =
                        GetPropertyValueRequestPacket::fromGenericPacket(receivedPacket);

                if (packet.isValid())
                {
                    handleReceivedGetPropertyValueRequestPacket(packet);
                }
                break;
            }

            case PacketType_GetPropertyValueResponse:
            {
                GetPropertyValueResponsePacket packet =
                        GetPropertyValueResponsePacket::fromGenericPacket(receivedPacket);

                if (packet.isValid())
                {
                    handleReceivedGetPropertyValueResponsePacket(packet);
                }
                break;
            }

            case PacketType_SetPropertyValueRequest:
            {
                handleReceivedSetPropertyValueRequestPacket(receivedPacket);
                break;
            }

            case PacketType_SetPropertyValueResponse:
            {
                handleReceivedSetPropertyValueResponsePacket(receivedPacket);
                break;
            }

            case PacketType_ExecuteMethodRequest:
            {
                handleReceivedExecuteMethodRequestPacket(receivedPacket);
                break;
            }

            case PacketType_ExecuteMethodResponse:
            {
                handleReceivedExecuteMethodResponsePacket(receivedPacket);
                break;
            }

            case PacketType_Event:
            {
                handleReceivedEventPacket(receivedPacket);
                break;
            }

            case PacketType_EventConfirmation:
            {
                handleReceivedEventConfirmationPacket(receivedPacket);
                break;
            }

            default:
            {
                // Ignore all unexpected packet types
                break;
            }
        }
    }
}

void AbstractSimpleNode::handleReceivedRegistrationRequestPacket(const RegistrationRequestPacket &)
{
    // Ignore
}

void AbstractSimpleNode::handleReceivedRegistrationResponsePacket(
        const RegistrationResponsePacket &)
{
    // Ignore
}

void AbstractSimpleNode::handleReceivedGetPropertyValueRequestPacket(
        const GetPropertyValueRequestPacket &packet)
{
    bool success = false;
    const quint16 propertyId = packet.getPropertyId();
    ResponseStatus errorCode = ResponseStatus_ParameterError;

    // Get property's access modifier
    const AccessModifier accessModifier = getPropertyAccessModifier(propertyId, &success);

    if (success &&
        (accessModifier != AccessModifier_ReadOnly) &&
        (accessModifier != AccessModifier_ReadWrite))
    {
        errorCode = ResponseStatus_AccessDenied;
        success = false;
    }

    // Get property's value
    const AbstractDataType *propertyValue = NULL;

    if (success)
    {
        propertyValue = getPropertyValue(propertyId, &success);

        if (success == false)
        {
            errorCode = ResponseStatus_ParameterError;
        }
        else
        {
            if (propertyValue == NULL)
            {
                errorCode = ResponseStatus_ParameterError;
                success = false;
            }
        }
    }

    // Prepare response packet
    GetPropertyValueResponsePacket responsePacket;

    responsePacket.setSource(packet.getDestination());
    responsePacket.setDestination(packet.getSource());
    responsePacket.setSequence(getNextSequence());
    responsePacket.setRequestSequence(packet.getSequence());

    if (success)
    {
        responsePacket.setResponseStatus(ResponseStatus_Success);
        responsePacket.setPropertyValue(propertyValue);
    }
    else
    {
        responsePacket.setResponseStatus(errorCode);
    }

    // Send response packet
    if (responsePacket.isValid())
    {
        sendPacket(responsePacket);
    }
}

void AbstractSimpleNode::handleReceivedGetPropertyValueResponsePacket(
        const GetPropertyValueResponsePacket &)
{
    // Ignore
}

void AbstractSimpleNode::handleReceivedSetPropertyValueRequestPacket(const GenericPacket &)
{
    // TODO: implement
}

void AbstractSimpleNode::handleReceivedSetPropertyValueResponsePacket(const GenericPacket &)
{
    // TODO: implement
}

void AbstractSimpleNode::handleReceivedExecuteMethodRequestPacket(const GenericPacket &)
{
    // TODO: implement
}

void AbstractSimpleNode::handleReceivedExecuteMethodResponsePacket(const GenericPacket &)
{
    // TODO: implement
}

void AbstractSimpleNode::handleReceivedEventPacket(const GenericPacket &)
{
    // TODO: implement
}

void AbstractSimpleNode::handleReceivedEventConfirmationPacket(const GenericPacket &)
{
    // TODO: implement
}
